/*
 ***************************************************************************************************
 *  isl29028.c 
 *  author:chenzhiwei
 *  vertion3.0
 *  mail:chenzhw@k-touch.cn
 *
 *  
 *  isl29028 chip register bind to sysfs virtual system
 *  light sensor
 *  proxmity sensor
 ****************************************************************************************************
 */


#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/isl29028.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <mach/hardware.h>

#include <linux/input.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/earlysuspend.h>
#include <linux/mutex.h>

#include <linux/miscdevice.h>
#include <linux/wakelock.h>
#include <linux/ioctl.h>


#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/pda_power.h>
#include <linux/io.h>
//#include <linux/usb/android_composite.h>
#include <linux/i2c.h>

#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/setup.h>

#include <mach/gpio.h>
#include <linux/regulator/consumer.h>

#include <linux/gpio.h>
#define MPU_PROX_IRQ_GPIO		49

#define  ID_TYPE_LIGHT   (1<<31)
#define  ID_TYPE_PROX    (1<<30)

static int g_print=0;



#define JIT_SENSOR_INTERVAL               (HZ/20)



#define ISL29028_DRV_NAME	"isl29028"
#define DRIVER_VERSION		"1.0.0"




//define register
#define ISL29028_ID		           0x00

#define ISL29028_CONFIG		       0x01

#define ISL29028_INTCONFIG		   0x02

#define ISL29028_PROX_LT		   0x03
#define ISL29028_PROX_HT		   0x04

#define ISL29028_ALSIR_TH1		   0x05
#define ISL29028_ALSIR_TH2		   0x06
#define ISL29028_ALSIR_TH3		   0x07

#define ISL29028_PROX_DATA		   0x08

#define ISL29028_ALSIR_DATA1	   0x09
#define ISL29028_ALSIR_DATA2	   0x0A

#define ISL29028_TEST1	   0x0E
#define ISL29028_TEST2	   0x0F

#define  LIGHT_DEFAULT (0xffff)

#define  LUX_CHANGE_IN_SUN_LIGHT  (20)
#define  LUX_CHANGE_IN_DOOR       (4)
#define  LUX_CHANGE_IN_DARK       (1)


#define  INT_CONFIG_CONST  0x02

#define ISL29028_CHIP_ID  (191)
#define ISL29028_100MA    (0)
#define ISL29028_200MA    (1<<3)

//define bit operations
#define  ms50  (0x05<<4)
#define  ms75  (0x04<<4)
#define  ms100 (0x03<<4)
#define  ms200 (0x02<<4)
#define  ms400 (0x01<<4)
#define  ms800 (0x00<<4)

#define  PROX_FLAG  (1<<7)
#define  ALS_FLAG   (1<<3)
#define  ALS_RANGE    (1<<1)
#define  ALS_EN       (1<<2)
#define  PROX_DR      (1<<3)
#define  PROX_EN      (1<<7)

#ifdef TY_KERNEL_SYS_LOG_EN
#define ENTER_FUNCTION  printk(KERN_ERR "==>Enter %s()\n",__func__)
#define EXIT_FUNCTION   printk(KERN_ERR "==>Exit  %s()\n",__func__)
#else
#define ENTER_FUNCTION /* printk("")  */
#define EXIT_FUNCTION  /* printk("") */
#endif


struct isl29028_data {
	struct isl29028_platform_data *pdata;
	struct early_suspend	early_suspend;
	struct i2c_client *client;
	struct mutex update_lock;
	struct delayed_work irq_work;
	struct delayed_work timer_work;
	struct input_dev *input_dev;
	int    state_als;
	int    state_prox;
	int    coff;
	spinlock_t lock;
	unsigned int test;

};





struct isl29028_data *isl29028_misc_data;



struct workqueue_struct *sensor_proxlight_wq; 
static struct wake_lock proxmity_wake_lock;



static unsigned int light_prev =LIGHT_DEFAULT;

static int irq_no;



static int   delay_light_min;
static int   delay_light_max; 
static int   delay_light;
static int   g_alsdata;
static int   g_proxdata=1;
static unsigned int suspend_flag =0;









static int sensor_i2c_write(struct i2c_adapter *i2c_adap,
		     unsigned char address,
		     unsigned int len, unsigned char const *data)
{
	struct i2c_msg msgs[1];
	int res;

	if (NULL == data || NULL == i2c_adap)
		return -EINVAL;

	msgs[0].addr = address;
	msgs[0].flags = 0;	/* write */
	msgs[0].buf = (unsigned char *) data;
	msgs[0].len = len;

	res = i2c_transfer(i2c_adap, msgs, 1);
	if (res < 1)
		return res;
	else
		return 0;
}

static int sensor_i2c_write_register(struct i2c_adapter *i2c_adap,
			      unsigned char address,
			      unsigned char reg, unsigned char value)
{
	unsigned char data[2];
//	printk("==jinjt== sensor_i2c_write_register address=0x%x, reg=0x%x value=0x%x\n", address, reg, value);
	data[0] = reg;
	data[1] = value;
	return sensor_i2c_write(i2c_adap, address, 2, data);
}

static int sensor_i2c_read(struct i2c_adapter *i2c_adap,
		    unsigned char address,
		    unsigned char reg,
		    unsigned int len, unsigned char *data)
{
	struct i2c_msg msgs[2];
	int res;
//	printk("==jinjt== set_isl29028_reg val=0x%x, reg=0x%x data=%p\n", val, reg, data);
	if (NULL == data || NULL == i2c_adap)
		return -EINVAL;

	msgs[0].addr = address;
	msgs[0].flags = 0;	/* write */
	msgs[0].buf = &reg;
	msgs[0].len = 1;

	msgs[1].addr = address;
	msgs[1].flags = I2C_M_RD;
	msgs[1].buf = data;
	msgs[1].len = len;

	res = i2c_transfer(i2c_adap, msgs, 2);
	if (res < 2)
		return res;
	else
		return 0;
}

static int  set_isl29028_reg(unsigned char val,int reg, struct isl29028_data *data )
{
	int ret;

//	printk("==jinjt== set_isl29028_reg val=0x%x, reg=0x%x data=%p\n", val, reg, data);
	ret =sensor_i2c_write_register(data->client->adapter,data->client->addr,reg, val);	
	if(ret != 0)
		printk( KERN_ERR "i2c write error of proxmitysensor addr=%d,reg=%d,val=%d\r\n",data->client->addr,reg,val);
		

	return ret;
}



static int  get_isl29028_reg_return(int reg,struct isl29028_data *data,unsigned char*regdata)
{
     unsigned char ret;

     ret = sensor_i2c_read(data->client->adapter,data->client->addr,reg,1, regdata);
	 if(ret != 0)
		printk( KERN_ERR "i2c read error of proxmitysensor addr=%d,reg=%d\r\n",data->client->addr,reg);
     

     return ret;
}




static ssize_t isl29028_show_intconfig(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct isl29028_data *data = i2c_get_clientdata(client);
	int ret=0;
	unsigned char reg;
	ENTER_FUNCTION;
//	printk("==jinjt== isl29028_show_intconfig dev=%p, attr=%p, buf=%s\n", dev, attr, buf);
	ret= get_isl29028_reg_return(ISL29028_INTCONFIG,data,&reg);
	EXIT_FUNCTION;
	return sprintf(buf, "%d\n", reg);;
}





static ssize_t isl29028_show_config(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	unsigned char reg;
	struct i2c_client *client = to_i2c_client(dev);
	struct isl29028_data *data = i2c_get_clientdata(client);
	int ret=0;;
	
	/* unsigned char reg; */
	ENTER_FUNCTION;
//	printk("==jinjt== isl29028_show_config dev=%p, attr=%p, buf=%s\n", dev, attr, buf);
	ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);


	EXIT_FUNCTION;
	return sprintf(buf, "%d\n", reg);;
}







static ssize_t isl29028_show_proxlow(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct isl29028_data *data = i2c_get_clientdata(client);
	int ret;
	
	unsigned char reg;
	ENTER_FUNCTION;
//	printk("==jinjt== isl29028_show_proxlow dev=%p, attr=%p, buf=%s\n",dev, attr, buf);
	ret= get_isl29028_reg_return(ISL29028_PROX_LT,data,&reg);

	EXIT_FUNCTION;
	return sprintf(buf, "%d\n", reg);
}

static ssize_t isl29028_show_proxhigh(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct isl29028_data *data = i2c_get_clientdata(client);
	int ret;

	unsigned char reg;
	ENTER_FUNCTION;
//	printk("==jinjt== isl29028_show_proxhigh dev=%p, attr=%p, buf=%s\n",dev, attr, buf);
	ret= get_isl29028_reg_return(ISL29028_PROX_HT,data,&reg);

	EXIT_FUNCTION;
	return sprintf(buf, "%d\n", reg);

}





static ssize_t isl29028_show_alslow(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct isl29028_data *data = i2c_get_clientdata(client);
	int ret;
	unsigned char reg;
	ENTER_FUNCTION;
//	printk("==jinjt== isl29028_show_alslow dev=%p, attr=%p, buf=%s\n",dev, attr, buf);
	ret= get_isl29028_reg_return(ISL29028_ALSIR_TH1,data,&reg);
	EXIT_FUNCTION;
	return sprintf(buf, "%d\n", reg);;
}


static ssize_t isl29028_show_alsmid(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct isl29028_data *data = i2c_get_clientdata(client);
	int ret;
	unsigned char reg;
	ENTER_FUNCTION;
//	printk("==jinjt== isl29028_show_alsmid dev=%p, attr=%p, buf=%s\n",dev, attr, buf);	
	ret= get_isl29028_reg_return(ISL29028_ALSIR_TH2,data,&reg);
	EXIT_FUNCTION;
	return sprintf(buf, "%d\n", reg);

}
static ssize_t isl29028_show_alshigh(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct isl29028_data *data = i2c_get_clientdata(client);
	int ret;
	unsigned char reg;
	ENTER_FUNCTION;
//	printk("==jinjt== isl29028_show_alshigh dev=%p, attr=%p, buf=%s\n",dev, attr, buf);
	ret= get_isl29028_reg_return(ISL29028_ALSIR_TH3,data,&reg);
	EXIT_FUNCTION;
	return 	sprintf(buf, "%d\n", reg);
	
}





//czwprox
static ssize_t isl29028_show_proxdata(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	/* struct i2c_client *client = to_i2c_client(dev); */
	/* struct isl29028_data *data = i2c_get_clientdata(client); */


	static unsigned char g_proxdatabak;
	/* unsigned long spinflags; */
	ENTER_FUNCTION;
//	printk("==jinjt== isl29028_show_proxdata dev=%p, attr=%p, buf=%s\n",dev, attr, buf);
	disable_irq(irq_no);
	g_proxdatabak = g_proxdata;
	enable_irq(irq_no);
	EXIT_FUNCTION;
	return 	sprintf(buf, "%d\n",  g_proxdatabak );
}

//czwals
static ssize_t isl29028_show_alsdata(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct isl29028_data *data = i2c_get_clientdata(client);
	static int g_alsdatabak;
	ENTER_FUNCTION;
//	printk("==jinjt== isl29028_show_alsdata dev=%p, attr=%p, buf=%s\n",dev, attr, buf);

	mutex_lock(&data->update_lock);
	g_alsdatabak =g_alsdata;
	mutex_unlock(&data->update_lock);

	EXIT_FUNCTION;
	return sprintf(buf, "%d\n", g_alsdatabak);

}




static ssize_t isl29028_getproxdata(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct isl29028_data *data = i2c_get_clientdata(client);
	int ret;
	int pin;

	unsigned char reg;
//	printk("==jinjt== isl29028_getproxdata dev=%p, attr=%p, buf=%s\n",dev, attr, buf);
	ret= get_isl29028_reg_return(ISL29028_PROX_DATA,data,&reg);
	
	pin = gpio_get_value(MPU_PROX_IRQ_GPIO);
	printk(KERN_DEBUG "==jinjt==  isl29028 , pin= %d\n", pin);
	return 	sprintf(buf, "%d\n",  reg );
}


static DEVICE_ATTR(getproxdata, S_IRUGO,isl29028_getproxdata, NULL);

static ssize_t isl29028_getalsdata(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct isl29028_data *data = i2c_get_clientdata(client);


	int ret;
	int onebyte=0;
	int twobyte=0;
	printk(KERN_DEBUG "==jinjt== isl29028_getalsdata dev=%p, attr=%p, buf=%s\n",dev, attr, buf);
	ret= get_isl29028_reg_return(ISL29028_ALSIR_DATA1,data,(unsigned char *)&onebyte);
	ret= get_isl29028_reg_return(ISL29028_ALSIR_DATA2,data,(unsigned char *)&twobyte);
	printk(KERN_DEBUG "==jinjt== isl29028_getalsdata onebyte=%d, twobyte=%d\n",onebyte, twobyte);
	ret = ((twobyte&0x0f)<<8)|(onebyte&0xff);
	return sprintf(buf, "%d\n", ret);
}



static DEVICE_ATTR(getalsdata, S_IRUGO,isl29028_getalsdata, NULL);
static DEVICE_ATTR(proxdata, S_IRUGO,isl29028_show_proxdata, NULL);
static DEVICE_ATTR(alsdata, S_IRUGO,isl29028_show_alsdata, NULL);
static DEVICE_ATTR(config,   S_IRUGO,isl29028_show_config,NULL);



static DEVICE_ATTR(intconfig, S_IRUGO,isl29028_show_intconfig, NULL);

static DEVICE_ATTR(proxlow, S_IRUGO,isl29028_show_proxlow, NULL);
static DEVICE_ATTR(proxhigh,  S_IRUGO,isl29028_show_proxhigh, NULL);

static DEVICE_ATTR(alslow, S_IRUGO,isl29028_show_alslow, NULL);
static DEVICE_ATTR(alsmid,  S_IRUGO,isl29028_show_alsmid, NULL);
static DEVICE_ATTR(alshigh, S_IRUGO,isl29028_show_alshigh, NULL);


static struct attribute *isl29028_attributes[] = {
	&dev_attr_config.attr,
	&dev_attr_intconfig.attr,
	&dev_attr_proxlow.attr,
	&dev_attr_proxhigh.attr,
	&dev_attr_alslow.attr,
	&dev_attr_alsmid.attr,
	&dev_attr_alshigh.attr,
	&dev_attr_proxdata.attr,
	&dev_attr_alsdata.attr,
	&dev_attr_getproxdata.attr,
	&dev_attr_getalsdata.attr,
	NULL
};

static const struct attribute_group isl29028_attr_group = {
	.attrs = isl29028_attributes,
};





static int isl29028_misc_open(struct inode *inode, struct file *file)
{
	int err;
//	printk("==jinjt== isl29028_misc_open inode=%p, file=%p",inode, file);
	err = nonseekable_open(inode, file);
	if (err < 0)
		return err;
	file->private_data = isl29028_misc_data;
	return 0;
}

static void sort(unsigned char *a,int n)
{
   unsigned char temp,min;
   int i,j;
//   printk("==jinjt== sort a=%s, n=%d\n",a,n);
   for(i=0;i<n;i++)
   {
	     min=i;
	     for( j=i+1;j<n;j++)
		if(a[j]<a[min])
		   min=j;
	     {
	       temp=a[i];
	       a[i]=a[min];
	       a[min]=temp;
	     }
   }
}

static int get_proxadjustment_data(struct isl29028_data *data)
{

        unsigned int cnt;
		int ret;
		unsigned char reg,intflag;

//		printk("==jinjt== get_proxadjustment_data data=%p\n",data);
	    ret= get_isl29028_reg_return(ISL29028_INTCONFIG,data,&intflag);
		if(ret != 0 ) return -1;
        
        cnt =0;
        while( (intflag &PROX_FLAG) == 0 )
        {
              mdelay(10);
              cnt++;
              if(cnt >=100)
                return -1;
              ret= get_isl29028_reg_return(ISL29028_INTCONFIG,data,&intflag);
			  if(ret != 0 ) return -1;
        }
		intflag &=(~PROX_FLAG);
		set_isl29028_reg(intflag,ISL29028_INTCONFIG,data);
		
        ret= get_isl29028_reg_return(ISL29028_PROX_DATA,data,&reg);
        if(ret != 0 ) return -1;
        return reg;

}


#define  PROXMITY_LOW_RANGE  (15)
#define  PROXMITY_MAX_RANGE  (20)

//czwioctl


/*
**********************************************************************************************
* check  disable_irq_nosync----enable_irq
* check  mutex_lock----------mutex_unlock
*
*
*
*
*
**********************************************************************************************
*/
#define  CURRENT_100MA (100 <<8)
#define  CURRENT_200MA (200 <<8)



/* static int isl29028_misc_ioctl(struct file *file, */
static long isl29028_misc_ioctl(struct file *file,
			      unsigned int cmd, unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	static   unsigned int  g_alsdatabak;
	static   unsigned char g_proxdatabak;
	unsigned int interval;
	static int timer_report_prox=0;
	int ret;
	int i;
	/* unsigned long spinflags; */
	unsigned char adj[10];
	/* unsigned char aver,val,onebyte,twobyte; */
	unsigned char aver,val;
	unsigned char reg,flags;
	unsigned long  delay;
	unsigned int current_proxmity;
	unsigned char intflag=0;
	int pin;

   

	struct isl29028_data *data = file->private_data;
//	printk("==jinjt== isl29028_misc_ioctl file=%p, cmd=%d, arg=%d\n", file, cmd, arg);
	
	switch (cmd) {

	case  ISL29028_IOCTL_SET_LIGHT_DELAY:   
          if (copy_from_user(&delay, argp, sizeof(delay)))
		     goto 	kmalloc_fail;
	
		  interval =delay/1000000;//transform  to ms
		
	      if(interval != 0)
		      delay_light = msecs_to_jiffies(interval);
		  else 
		      delay_light = delay_light_min;
		  
		  if( delay_light >=delay_light_max )
		      delay_light=delay_light_max;
		  if( delay_light <=delay_light_min )
		      delay_light=delay_light_min;	
//		  printk(KERN_ERR "==jinjt==ISL29028_IOCTL_SET_LIGHT_DELAY jifft=%d\r\n",delay_light);
       
	      break;
	case ISL29028_IOCTL_SET_PROXMITY_DELAY:   
		if (copy_from_user(&delay, argp, sizeof(delay)))
			goto 	kmalloc_fail; 
		interval =delay/1000000;//transform to ms
//		printk(KERN_ERR "==jinjt==ISL29028_IOCTL_SET_PROXMITY_DELAY ms=%d\r\n",interval);

		if( timer_report_prox ==( interval/10) )//compare history and current ,if equal without reset delay reg
		{
			break;
		}
		//reset dealy register
		timer_report_prox =interval/10;
		if(timer_report_prox == 0)
			timer_report_prox = 20;

		ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&val);
		if( ret != 0 ); break;

		val &=~(0x07<<4);
		if(timer_report_prox <=10)
		val|=ms100;
		else if(timer_report_prox <=20)
		{
			val|=ms200;
		}
		else if(timer_report_prox  <=40)
		{
			val|=ms400;
		}
		else 
			val|=ms800;
		set_isl29028_reg(val,ISL29028_CONFIG,data);
		break;

	case ISL29028_IOCTL_SET_ALSFLAG:
		if (copy_from_user(&interval, argp, sizeof(interval)))
			goto 	kmalloc_fail;

		data->state_als = interval;
		if(suspend_flag == 1)
		{
			/* printk(KERN_INFO "==jinjt==ISL29028_IOCTL_SET_ALSFLAG data->state_als=%d action is in early_suspend or late_resume suspend_flag=%d\n",data->state_als,suspend_flag); */
			break;
		}
		if (data->state_als )
		{

			mutex_lock(&data->update_lock);
			ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
			if( ret != 0 ) break;
			reg|=ALS_EN;
			set_isl29028_reg(reg,ISL29028_CONFIG,data);
			data->state_als =1 ;
			light_prev = LIGHT_DEFAULT;
	#if 0 
			msleep(120);
			ret= get_isl29028_reg_return(ISL29028_ALSIR_DATA1,data,&onebyte);
			ret= get_isl29028_reg_return(ISL29028_ALSIR_DATA2,data,&twobyte);
			g_alsdata = ((twobyte&0x0f)<<8)|(onebyte&0xff);
	#endif
			mutex_unlock(&data->update_lock);
		    queue_delayed_work(sensor_proxlight_wq, &data->timer_work, delay_light);
	        printk(KERN_INFO "==jinjt==ISL29028_IOCTL_SET_ALSFLAG data->state_als=%d\n",data->state_als);
			
		}
		else
		{
			mutex_lock(&data->update_lock);
			ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
			reg&=~ALS_EN;
			set_isl29028_reg(reg,ISL29028_CONFIG,data);
			data->state_als =0 ;
	        printk(KERN_INFO "==jinjt==ISL29028_IOCTL_SET_ALSFLAG data->state_als=%d\n",data->state_als);
			mutex_unlock(&data->update_lock);
			
			if ( cancel_delayed_work(&data->timer_work) == 0)
			{
				 flush_workqueue(sensor_proxlight_wq);
//				printk(KERN_INFO "==jinjt==ISL29028_IOCTL_SET_ALSFLAG cancel timer work success! \r\n");
				if ( cancel_delayed_work(&data->timer_work) == 0)
				{
//					 printk(KERN_CRIT "==jinjt==ISL29028_IOCTL_SET_ALSFLAG cancel timer work again success! \r\n");
					 flush_workqueue(sensor_proxlight_wq);
				}
			}
			
		}
	    break;


	case ISL29028_IOCTL_SET_PROXFLAG:
		if (copy_from_user(&interval, argp, sizeof(interval)))
			goto 	kmalloc_fail;
		
		data->state_prox= interval;
		disable_irq(irq_no);
		
		if (data->state_prox)
		{
			ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
			reg|=PROX_EN;
			set_isl29028_reg(reg,ISL29028_CONFIG,data);

			flags = INT_CONFIG_CONST|PROX_FLAG;
			set_isl29028_reg(flags,ISL29028_INTCONFIG,data);
            printk(KERN_INFO "==jinjt==ISL29028_IOCTL_SET_PROXFLAG prox_en = 1\r\n");
        }

		else
		{
			flags = INT_CONFIG_CONST|PROX_FLAG;
			set_isl29028_reg(flags,ISL29028_INTCONFIG,data);
			ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
			reg&=~PROX_EN;
			set_isl29028_reg(reg,ISL29028_CONFIG,data);
            printk(KERN_INFO "==jinjt==ISL29028_IOCTL_SET_PROXFLAG prox_en = 0\r\n");
		}

		enable_irq(irq_no);
	
		break;

	case ISL29028_IOCTL_GET_ALSDATA:
		mutex_lock(&data->update_lock);
		g_alsdatabak =g_alsdata;
		mutex_unlock(&data->update_lock);
		if (copy_to_user(argp, &g_alsdatabak, sizeof(g_alsdatabak)))
		goto 	kmalloc_fail;
//        printk(KERN_ERR "==jinjt==ISL29028_IOCTL_GET_ALSDATA\r\n");
		break;

	case ISL29028_IOCTL_GET_PROXDATA:
	
		disable_irq(irq_no);
		g_proxdatabak = g_proxdata;
		enable_irq(irq_no);
		
		if (copy_to_user(argp, &g_proxdatabak, sizeof(g_proxdatabak)))
		goto 	kmalloc_fail;
//        printk(KERN_ERR "==jinjt==ISL29028_IOCTL_GET_PROXDATA g_proxdatabak=%d,g_proxdata=%d\r\n",g_proxdatabak,g_proxdata);
		break;



	case ISL29028_IOCTL_GET_ADJUSEMENT:
		disable_irq(irq_no);
	    current_proxmity =0;
		if(set_isl29028_reg(0,ISL29028_PROX_LT,data) != 0)
			goto i2c_fail;
		if(set_isl29028_reg(0,ISL29028_PROX_HT,data) != 0)
			goto i2c_fail;  
//        printk(KERN_ERR "==jinjt==ISL29028_IOCTL_GET_ADJUSEMENT\r\n");
		ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);

		reg|=PROX_EN;
		reg|=ISL29028_200MA;
		set_isl29028_reg(reg,ISL29028_CONFIG,data);

		for(i=0; i<5;i++)
		{
	          ret = get_proxadjustment_data(data);
//			  printk("==jinjt== 1 get adjusement i=%d, ret=%d\n",i,ret);
		      if(ret < 0 )
			  goto i2c_fail;
		      adj[i]=ret&0xff;
		}

		
		ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
		reg&=~PROX_EN;
		set_isl29028_reg(reg,ISL29028_CONFIG,data);
		//sort
		sort(adj,5);
		aver=(adj[1]+adj[2]+adj[3])/3;
	    printk(KERN_INFO "1=%d,2=%d,3=%d,4=%d,5=%d,aver=%d\r\n",adj[0],adj[1],adj[2],adj[3],adj[4],aver);

		if(aver >=140)
		{		//set 100ms curretnt
			
			ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
			reg|=PROX_EN;
			reg&=(~ISL29028_200MA);
			set_isl29028_reg(reg,ISL29028_CONFIG,data);
			for(i=0; i<5;i++)
			{
				  ret = get_proxadjustment_data(data);
//				printk("==jinjt== 2 get adjusement i=%d, ret=%d\n",i,ret);
				  if(ret <0 )
				  goto i2c_fail;
				  adj[i]=ret&0xff;
			}
			ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
			reg&=~PROX_EN;
			set_isl29028_reg(reg,ISL29028_CONFIG,data);  
	//sort
			sort(adj,5);
			aver=(adj[1]+adj[2]+adj[3])/3;
			printk(KERN_INFO"curent = 100ma 1=%d,2=%d,3=%d,4=%d,5=%d,aver=%d\n",adj[0],adj[1],adj[2],adj[3],adj[4],aver);
			current_proxmity |=CURRENT_100MA;  
	    }
	 	else
		{
			 current_proxmity |=CURRENT_200MA;
			 
		}
	   current_proxmity |=aver;


		//according the base refrect ,dynamic adjust the parameter
//		printk("==jinjt== 3 get adjusement aver=%d", aver);
		if(aver < 200)
		{
			if(set_isl29028_reg(aver+PROXMITY_LOW_RANGE,ISL29028_PROX_LT,data)!=0)
				goto i2c_fail;
			if(set_isl29028_reg(aver+PROXMITY_MAX_RANGE,ISL29028_PROX_HT,data)!=0)
				goto i2c_fail;

		}
		else
		{
			if(set_isl29028_reg(255,ISL29028_PROX_LT,data) != 0 )
				goto i2c_fail;  
			if(set_isl29028_reg(255,ISL29028_PROX_HT,data) != 0 )
				goto i2c_fail;

		}

		//-------------------------------------------------------
		get_isl29028_reg_return(ISL29028_INTCONFIG,data,&intflag);
		intflag &=(~PROX_FLAG);
		set_isl29028_reg(intflag,ISL29028_INTCONFIG,data);
		g_proxdata =1;
        pin = gpio_get_value(MPU_PROX_IRQ_GPIO);

		if(pin)
		{
			irq_set_irq_type(irq_no, IRQ_TYPE_LEVEL_LOW );
		}
		else
		{
			irq_set_irq_type(irq_no, IRQ_TYPE_LEVEL_HIGH);
		}
		//------------------------------------------------------
		enable_irq(irq_no);
		if (copy_to_user(argp, &current_proxmity, sizeof(current_proxmity)))
		goto 	kmalloc_fail;

		break;


	case ISL29028_IOCTL_SET_ADJUSEMENT:
		if (copy_from_user(&current_proxmity, argp, sizeof(current_proxmity)))
			goto	kmalloc_fail;
//		printk("==jinjt== set adjusement current_proxmity=%d, argp=%d\n",current_proxmity,argp);
		disable_irq(irq_no);

		if( (current_proxmity & CURRENT_100MA) == CURRENT_100MA )
        {
	        ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
	        printk(KERN_INFO "----open  mobil to set 100 ma\r\n");

		//	reg|=PROX_EN;
			reg&=(~ISL29028_200MA);
			set_isl29028_reg(reg,ISL29028_CONFIG,data);
        }
        else  if( (current_proxmity & CURRENT_200MA) == CURRENT_200MA )
        {
			printk(KERN_INFO "----open  mobil to set 200 ma\r\n");
			ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
		//	reg|=PROX_EN;
			reg|=(ISL29028_200MA);
			set_isl29028_reg(reg,ISL29028_CONFIG,data);
		}
        else
        {
			printk(KERN_ERR "----open  mobil to set current is not be supported\r\n");
        }
        aver =(current_proxmity & 0xff) ;
		
//		printk("==jinjt 2 set adjusement aver=%d\n",aver);
		if(aver <200)
		{

			if(set_isl29028_reg(aver+PROXMITY_LOW_RANGE,ISL29028_PROX_LT,data)!=0)
				goto i2c_fail;
			if(set_isl29028_reg(aver+PROXMITY_MAX_RANGE,ISL29028_PROX_HT,data)!=0)
				goto i2c_fail;

		}
		else
		{

			if(set_isl29028_reg(255,ISL29028_PROX_LT,data)!=0)
				goto i2c_fail;
			if(set_isl29028_reg(255,ISL29028_PROX_HT,data)!=0)
				goto i2c_fail;

		}
//-------------------------------------------------------------------------
		get_isl29028_reg_return(ISL29028_INTCONFIG,data,&intflag);
		intflag &=(~PROX_FLAG);
		set_isl29028_reg(intflag,ISL29028_INTCONFIG,data);
		g_proxdata =1;
		pin = gpio_get_value(MPU_PROX_IRQ_GPIO);

		if(pin)
		{
			irq_set_irq_type(irq_no, IRQ_TYPE_LEVEL_LOW );
		}
		else
		{
			irq_set_irq_type(irq_no, IRQ_TYPE_LEVEL_HIGH);
		}
//-------------------------------------------------------------------------
        enable_irq(irq_no);
//		printk("==jinjt== 3 set adjusement success \n");
		break;

	default:
	    return -EINVAL;
	}
	
	return 0;
i2c_fail:
	enable_irq(irq_no);
	printk(KERN_ERR "set adjust proxdata fail----error\r\n");
kmalloc_fail:
	return -1;
}

static const struct file_operations isl29028_misc_fops = {
	.owner = THIS_MODULE,
	.open =  isl29028_misc_open,
#if HAVE_COMPAT_IOCTL
	.compat_ioctl = isl29028_misc_ioctl,
#endif
#if HAVE_UNLOCKED_IOCTL
	.unlocked_ioctl = isl29028_misc_ioctl,
#endif
//	.compat_ioctl= isl29028_misc_ioctl,
};

static struct miscdevice isl29028_misc_device = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "isl29028",
	.fops = &isl29028_misc_fops,
};










/*
****************************************************************************************************
*  check lock
*  i2c fail process: 
*  read light sensor data ,if i2c fail have lost light data,because light data is not important
*  
* delay_light: have default value,the value come from the isl29028 data sheet 
* hal layer will set  delay_light value.
****************************************************************************************************
*/
static void isl29028_timerwork_func(struct work_struct *work)
{


	unsigned char onebyte,twobyte;
	unsigned int ret;
	unsigned int ref_lux;
	unsigned char reg;
	int result;
	int i;

	struct isl29028_data *data;
	/* struct isl29028_data *data = container_of(work, struct isl29028_data, timer_work); */
	const typeof( ((struct isl29028_data *)0)->timer_work ) *__mptr = (struct delayed_work*)(work);
	data = (struct isl29028_data *)( (char *)__mptr - offsetof(struct isl29028_data,timer_work) );
//	printk("==jinjt== isl29028_timerwork_func work=%p\n", work);
	mutex_lock(&data->update_lock);
//	printk(KERN_ERR "isl29028_timerwork_func delay_light=%d\r\n",delay_light);

	for(i =0;i<5;i++)
	{
		ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
		if( ret != 0 )
		{
		   	continue;
		}
		else
		{
			break;
		}
	}
	if(ret != 0)
	{
//		printk(KERN_CRIT "isl29028 reg return error!");
//		goto normal;
		goto isl29028_timerwork_func_errout;
	}
	reg&=ALS_EN;
    if(reg != ALS_EN)
	{
//		printk(KERN_CRIT "isl29028_timerwork_func should quit at once !");
		goto fail;
	}

/* normal: */

	ret= get_isl29028_reg_return(ISL29028_ALSIR_DATA1,data,&onebyte);
	if( ret != 0)
		goto isl29028_timerwork_func_errout;
	ret= get_isl29028_reg_return(ISL29028_ALSIR_DATA2,data,&twobyte);
	if( ret != 0)
		goto isl29028_timerwork_func_errout;

    ret =0;
	ret = twobyte&0x0f;
	ret =ret <<8;
	ret|=onebyte;
//	printk(KERN_ERR "isl29028_timerwork_func data->coff=%d\r\n",data->coff);
check:
	if( data->coff )
	{
//		change als to small range
		if(ret < 255)
		{
	        result= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
			if(result!=0)
				goto isl29028_timerwork_func_errout;
//	        printk(KERN_ERR "==jinjt==----open  mobil to set small range \r\n");
			reg&=(~ALS_RANGE);
			set_isl29028_reg(reg,ISL29028_CONFIG,data);
			data->coff = 0;
			ret = 4094;
			goto check;
		}
		ret =  (ret*522) /1000;
//		ret= ( ret * 10 )/26;
	}
	else
	{
//		change als to large range
		if(ret == 4095)
		{
	        result= get_isl29028_reg_return(ISL29028_CONFIG,data,&reg);
			if(result!=0)
				goto isl29028_timerwork_func_errout;
//	        printk(KERN_ERR "==jinjt==----open  mobil to set large range \r\n");
			reg|=(ALS_RANGE);
			set_isl29028_reg(reg,ISL29028_CONFIG,data);
			data->coff = 1;
			ret = 255;
			goto check;
		}
		ret = ( ret * 326 ) /10000;
//		ret= ( ret * 10 )/26;
	}
//	printk(KERN_ERR "isl29028_timerwork_func ret=%d\r\n",ret);
	if(ret > 100)
		ref_lux=LUX_CHANGE_IN_SUN_LIGHT;
	else  if(ret > 10)
		ref_lux=LUX_CHANGE_IN_DOOR;
	else 
		ref_lux=LUX_CHANGE_IN_DARK;
	
	if(ret >light_prev)
	{
		if(ret >= (light_prev+    ref_lux))
		{
		
			g_alsdata = ret;
		

			light_prev = ret;
//			light_prev = light_prev + ref_lux;
		}
	}
	else
	{
		if(light_prev >=(ret+    ref_lux) )
		{
			
			g_alsdata = ret;
			
			light_prev = ret;
//			light_prev = light_prev - ref_lux;
		}
	}
isl29028_timerwork_func_errout:	
	 mutex_unlock(&data->update_lock);

	//printk(KERN_ERR "isl29028_timerwork_func delay_light=%d,alsdata=%d\r\n",delay_light,g_alsdata);

	 queue_delayed_work(sensor_proxlight_wq, &data->timer_work, delay_light);
	goto end;
fail:
	 mutex_unlock(&data->update_lock);
end:
	return;
}





static irqreturn_t isl29028_isr(int irq, void *dev_id)
{
  
	/* struct isl29028_data *data = dev_id; */
	/* unsigned long spinflags; */
	int pin;
	disable_irq_nosync(irq);
	pin = gpio_get_value(MPU_PROX_IRQ_GPIO);
	printk("==jinjt==  sl29028_isr  irq=%d, pin= %d\n", irq, pin);
	if(pin == 0)
		g_proxdata =0;	
	else 
		g_proxdata = 1 ;
	
	if(pin)
	{
    	//printk("==jinjt== pin==1 29028_isr  irq=%d, pin= %d\n", irq, pin);
		irq_set_irq_type(irq_no, IRQ_TYPE_LEVEL_LOW );
	}
	else
	{
    	//printk("==jinjt== pin==0 29028_isr  irq=%d, pin= %d\n", irq, pin);
		irq_set_irq_type(irq_no, IRQ_TYPE_LEVEL_HIGH);
	}
	enable_irq(irq);
	wake_lock_timeout(&proxmity_wake_lock, 4 * HZ);
	return IRQ_HANDLED;


}



//static unsigned int suspend_flag =0;
static unsigned int wake_en=0;

/*
 **********************************************************************************
 *  if light sensor is enabled ,close light sensor power
 *  i2c fail without process
 *
 *
 **********************************************************************************
 */
void tegra_light_early_suspend(struct early_suspend *h)
{

	unsigned char val;
	int ret;
	/* unsigned long spinflags; */
	struct isl29028_data *data =container_of(h, struct isl29028_data, early_suspend);
	printk(KERN_INFO " tegra_light_early_suspend enter \n");
#if 1
	if ( (wake_en == 0 ) && device_may_wakeup(&data->client->dev))
	{
		if( enable_irq_wake(data->client->irq)== 0)
		{
			 wake_en=1;
		}	
	}
#endif
	wake_lock_timeout(&proxmity_wake_lock, 3 * HZ);
#if 0
	if( data->state_als == 0  )
		return;
#endif
	suspend_flag=1;

	if ( cancel_delayed_work(&data->timer_work) == 0)
	{
         flush_workqueue(sensor_proxlight_wq);
//		 printk(KERN_INFO "==jinjt==early_suspend cancel timer work success! \r\n");
		if ( cancel_delayed_work(&data->timer_work) == 0)
		{
	         flush_workqueue(sensor_proxlight_wq);
//			 printk(KERN_CRIT "==jinjt==early_suspend cancel timer work again success! \r\n");
		}
	}


	ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&val);
	if( ret != 0)
		return;

	if (data->state_als)
	{
		val &= ~ALS_EN;
		set_isl29028_reg(val,ISL29028_CONFIG,data);

	}
	printk(KERN_INFO "==jinjt==tegra_light_early_suspend data->state_als=%d \n",data->state_als);
//	printk(KERN_INFO "tegra_light_early_suspend exit \n");



	
}


/*
 **********************************************************************************
 *
 *
 *
 **********************************************************************************
 */

void tegra_light_late_resume(struct early_suspend *h)
{

	unsigned char val;
	int ret;
	struct isl29028_data *data =container_of(h, struct isl29028_data, early_suspend);
	printk(KERN_INFO "tegra_light_late_resume \n");
	wake_lock_timeout(&proxmity_wake_lock, 4 * HZ);
#if 1
	if ( (wake_en) && device_may_wakeup(&data->client->dev))
	{
		disable_irq_wake(data->client->irq);
		wake_en=0;
	} 
#endif 

	if(suspend_flag==0)
		return ;

	suspend_flag=0;
	ret= get_isl29028_reg_return(ISL29028_CONFIG,data,&val);
	if( ret != 0)
		return ;
	if (data->state_als)
	{
		val |= ALS_EN;
		set_isl29028_reg(val,ISL29028_CONFIG,data);
	    queue_delayed_work(sensor_proxlight_wq, &data->timer_work, delay_light);
	
	}
	printk(KERN_INFO "==jinjt==tegra_light_late_resume data->state_als=%d\n",data->state_als);
	light_prev = LIGHT_DEFAULT;
//	printk(KERN_INFO "==jinjt==tegra_light_late_resume exit\n");
}










static struct i2c_driver isl29028_driver;
/*
 *******************************************************************
 *resource requst order
exit_malloc
exit_sysfs
exit_queue
exit_misc
exit_irq
********************************************************************
*/

struct sensor_regulator {
	struct regulator *vreg;
	const char *name;
	u32	min_uV;
	u32	max_uV;
};

static struct sensor_regulator mpu_vreg[] = {
	{NULL, "vdd", 2850000, 2850000},	
	//{NULL, "vddio", 1800000, 1800000},

};
//{NULL, "8038_s2", 1800000, 1800000},
    	//{NULL, "8921_s2", 1800000, 1800000},
	//{NULL, "vlogic", 1800000, 1800000},

static int sensor_config_regulator(struct i2c_client *client, bool on)
{
	int rc = 0, i;
	int num_reg = sizeof(mpu_vreg) / sizeof(struct sensor_regulator);

	if (on) {
		for (i = 0; i < num_reg; i++) {
			mpu_vreg[i].vreg = regulator_get(&client->dev,
						mpu_vreg[i].name);
			if (IS_ERR(mpu_vreg[i].vreg)) {
				rc = PTR_ERR(mpu_vreg[i].vreg);
				pr_err("%s:regulator get failed rc=%d\n",
						__func__, rc);
				goto error_vdd;
			}

			if (regulator_count_voltages(mpu_vreg[i].vreg) > 0) {
				rc = regulator_set_voltage(mpu_vreg[i].vreg,
					mpu_vreg[i].min_uV, mpu_vreg[i].max_uV);
				if (rc) {
					pr_err("%s:set_voltage failed rc=%d\n",
						__func__, rc);
					regulator_put(mpu_vreg[i].vreg);
					goto error_vdd;
				}
			}

			rc = regulator_enable(mpu_vreg[i].vreg);
			if (rc) {
				pr_err("%s: regulator_enable failed rc =%d\n",
						__func__,
						rc);

				if (regulator_count_voltages(
					mpu_vreg[i].vreg) > 0) {
					regulator_set_voltage(mpu_vreg[i].vreg,
						0, mpu_vreg[i].max_uV);
				}
				regulator_put(mpu_vreg[i].vreg);
				goto error_vdd;
			}
		}
		return rc;
	} else {
		i = num_reg;
	}
error_vdd:
	while (--i >= 0) {
		if (regulator_count_voltages(mpu_vreg[i].vreg) > 0) {
			regulator_set_voltage(mpu_vreg[i].vreg, 0,
						mpu_vreg[i].max_uV);
		}
		regulator_disable(mpu_vreg[i].vreg);
		regulator_put(mpu_vreg[i].vreg);
	}
	return rc;
}



static int __devinit isl29028_probe(struct i2c_client *client,
				   const struct i2c_device_id *id)
{

	struct isl29028_data *data;
	/* struct input_dev *input; */
	int err = 0;
    int i;
	/* int ret; */
	unsigned char val;
//	struct regulator *whistler_light_2v85 = NULL;

	unsigned char chip_id=0;
	g_print = 0;
	pr_info("isl29028_probe\n");
	printk(KERN_INFO "isl29028_probe \n");
	sensor_config_regulator(client,1);
	mdelay(100);
//#ifndef TYN_MPU_3050
#if 0
	

	if (!whistler_light_2v85) 
    {
            whistler_light_2v85 = regulator_get(NULL, "vdd");
            if (IS_ERR_OR_NULL(whistler_light_2v85)) 
            {
                pr_err("isl29028: couldn't get regulator avdd_hdmi\n");
                whistler_light_2v85 = NULL;
                return  0;
            }
    }
	regulator_enable(whistler_light_2v85);
	regulator_set_voltage(whistler_light_2v85, 2850000, 2850000);
#endif



    wake_lock_init(&proxmity_wake_lock, WAKE_LOCK_SUSPEND, "proxmity_sensor");
	data = kzalloc(sizeof(struct isl29028_data), GFP_KERNEL);
	if (!data) {
		err = -ENOMEM;
		goto exit_malloc;
	}

	data->client = client;
	i2c_set_clientdata(client, data);

	set_isl29028_reg(0x00,0x01,data);
	set_isl29028_reg(0x29,0x0f,data);
	set_isl29028_reg(0x00,0x0e,data);
	set_isl29028_reg(0x00,0x0f,data);
	mdelay(250);
	for(i = 0 ; i< 10 ; i++ )
	{
		set_isl29028_reg(0x55,ISL29028_CONFIG,data);
		get_isl29028_reg_return(ISL29028_CONFIG,data,&chip_id);
		printk(KERN_INFO "---------isl29028 chip id-----------=0x%x\r\n",chip_id);
		if(chip_id == 0x55)
			break;
	}
//	if (i >=10)
//		goto exit_malloc;
	set_isl29028_reg(0x00,ISL29028_CONFIG,data);

	mutex_init(&data->update_lock);
	spin_lock_init(&data->lock);
	err = sysfs_create_group(&client->dev.kobj, &isl29028_attr_group);
	if (err)
		goto exit_sysfs;

	//-----------early suspend-----------------------------------------------
	   data->state_prox = 0;
#ifdef CONFIG_HAS_EARLYSUSPEND
	data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN+2;
	data->early_suspend.suspend = tegra_light_early_suspend;
	data->early_suspend.resume = tegra_light_late_resume;
	register_early_suspend(&data->early_suspend);
#endif

	dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);

	sensor_proxlight_wq = create_workqueue("sensor_proxlight");
	if (sensor_proxlight_wq == NULL) {
			printk(KERN_ERR "sensor_proxlight_wq: couldn't create workqueue\n");
			goto exit_queue;
	}


	INIT_DELAYED_WORK(&data->timer_work, isl29028_timerwork_func);

	isl29028_misc_data = data;
	

	err = misc_register(&isl29028_misc_device);
	if (err < 0) {
		dev_err(&client->dev, "isl29028_device register failed\n");
		goto exit_misc;
	}
#if 0
	err = request_threaded_irq(data->client->irq, NULL, isl29028_isr,
				   IRQF_TRIGGER_FALLING/*IRQF_TRIGGER_LOW | IRQF_ONESHOT*/,
				   "isl29028_irq", data);
#endif
#if 0
	err = request_irq(data->client->irq, isl29028_isr, IRQF_TRIGGER_LOW, "isl29028_irq", data);
//	err = request_irq(data->client->irq, isl29028_isr, IRQF_TRIGGER_FALLING, "isl29028_irq", data);
	if (err < 0) {
		dev_err(&client->dev, "failed to request irq %d\n",
			data->client->irq);
		goto exit_irq;
	}

	irq_no = data->client->irq;
#endif



	set_isl29028_reg(0,ISL29028_ALSIR_TH1,data);//[2048--3072]
	set_isl29028_reg(0xf0,ISL29028_ALSIR_TH2,data);
	set_isl29028_reg(0xff,ISL29028_ALSIR_TH3,data);
	set_isl29028_reg(0x00,ISL29028_PROX_LT,data);
	set_isl29028_reg(0xff,ISL29028_PROX_HT,data);
	
	set_isl29028_reg(2,ISL29028_INTCONFIG,data);
	set_isl29028_reg(51+ISL29028_200MA,ISL29028_CONFIG,data);
//	set_isl29028_reg(49+ISL29028_200MA,ISL29028_CONFIG,data);
#if 1
	err = request_irq(data->client->irq, isl29028_isr, IRQF_TRIGGER_FALLING, "isl29028_irq", data);
//	err = request_irq(data->client->irq, isl29028_isr, IRQF_TRIGGER_FALLING, "isl29028_irq", data);
	if (err < 0) {
		dev_err(&client->dev, "failed to request irq %d\n",
			data->client->irq);
		goto exit_irq;
	}

	irq_no = data->client->irq;
#endif
	get_isl29028_reg_return(ISL29028_CONFIG,data,&val);
	if(val &  ALS_RANGE)
	    data->coff = 1;
	else
	    data->coff = 0;
	device_init_wakeup(&data->client->dev, 1);


	data->test =0x55;
	delay_light_min = msecs_to_jiffies(100);
	delay_light_max = msecs_to_jiffies(1000);
	delay_light=delay_light_min;

    return 0;


exit_irq:
	free_irq(data->client->irq, data);
exit_misc:
	misc_deregister(&isl29028_misc_device);
exit_queue:
	destroy_workqueue(sensor_proxlight_wq);

#ifdef CONFIG_HAS_EARLYSUSPEND	
	unregister_early_suspend(&data->early_suspend);
#endif
exit_sysfs:
	sysfs_remove_group(&client->dev.kobj, &isl29028_attr_group);

exit_malloc:
	kfree(data);
    wake_lock_destroy(&proxmity_wake_lock);

	return err;
}




static int __devexit isl29028_remove(struct i2c_client *client)
{
 
	struct isl29028_data *data = i2c_get_clientdata(client);
//	printk("==jinjt== isl29028_remove client=%p\n", client);
	
	if ( cancel_delayed_work(&data->timer_work) == 0)
	{
         flush_workqueue(sensor_proxlight_wq);
//		 printk(KERN_INFO "==jinjt==isl29028_remove cancel timer work success! \r\n");
		if ( cancel_delayed_work(&data->timer_work) == 0)
		{
	         flush_workqueue(sensor_proxlight_wq);
//			 printk(KERN_CRIT "==jinjt==isl29028_remove cancel timer work again success! \r\n");
		}
	}
	
	free_irq(data->client->irq, data);
	misc_deregister(&isl29028_misc_device);
	sysfs_remove_group(&client->dev.kobj, &isl29028_attr_group);
	kfree(data);
	wake_lock_destroy(&proxmity_wake_lock);
	destroy_workqueue(sensor_proxlight_wq);
	return 0;
}




static const struct i2c_device_id isl29028_id[] = {
	{ "isl29028", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, isl29028_id);

static struct i2c_driver isl29028_driver = {
	.driver = {
		.name	= ISL29028_DRV_NAME,
		.owner	= THIS_MODULE,
	},
	.probe	= isl29028_probe,
	.remove	= __devexit_p(isl29028_remove),
	.id_table = isl29028_id,
};

static int __init isl29028_init(void)
{
	printk(KERN_INFO "isl29028_init \n");
	return i2c_add_driver(&isl29028_driver);
}

static void __exit isl29028_exit(void)
{
	printk(KERN_INFO "isl29028_exit \n");
	i2c_del_driver(&isl29028_driver);
}

MODULE_AUTHOR("chenzhiwei");
MODULE_DESCRIPTION("ISL29028 ambient light and prox sensor driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);

module_init(isl29028_init);
module_exit(isl29028_exit);



